package com.ltu.controller;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.core.util.Assert;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.dom4j.DocumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ltu.base.State;
import com.ltu.config.shiro.ShiroUtil;
import com.ltu.config.shiro.dto.UserDto;
import com.ltu.domain.mp_entity.OrderEntity;
import com.ltu.domain.mp_entity.PayRecord;
import com.ltu.domain.mp_entity.UserEntity;
import com.ltu.domain.mp_entity.customize.CompanyEntity;
import com.ltu.domain.mp_entity.customize.ProductServiceEntity;
import com.ltu.domain.mp_entity.customize.RefunRecordEntity;
import com.ltu.domain.mp_entity.customize.ServiceOrderEntity;
import com.ltu.enums.OrderEnums.OrderSource;
import com.ltu.mapper.OrderMapper;
import com.ltu.model.request.base.BaseFilterPageReq;
import com.ltu.model.request.order.PlaceOrderReq;
import com.ltu.model.response.base.CodeDataResp;
import com.ltu.model.response.excel.OrderRecordVO;
import com.ltu.model.response.order.OrderVO;
import com.ltu.payment.PubPayService;
import com.ltu.payment.WxPayServices2;
import com.ltu.payment.config.WxAppPayConfig;
import com.ltu.payment.enums.PayWayDict;
import com.ltu.payment.util.SignUtils;
import com.ltu.payment.util.XmlUtils;
import com.ltu.redis.lock.AmountLockService;
import com.ltu.rest.wxlive.WxMaLiveRestService;
import com.ltu.service.AccountService;
import com.ltu.service.OrderDetailService;
import com.ltu.service.OrderService;
import com.ltu.service.PayRecordService;
import com.ltu.service.UserService;
import com.ltu.service.customize.CompanyService;
import com.ltu.service.customize.ProductServiceService;
import com.ltu.service.customize.RefunRecordService;
import com.ltu.service.customize.ServiceOrderService;
import com.ltu.service.customize.WalletRecordService;
import com.ltu.service.impl.BaseServiceImpl;
import com.ltu.util.IpUtil;
import com.ltu.util.common.MpPageUtil;
import com.ltu.util.common.StrUtils;
import com.ltu.util.datetime.DateUtils;
import com.ltu.util.exception.ApiException;
import com.ltu.util.http.HttpPostUtil;
import com.ltu.vo.XcxUserOrderCountVO;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import springfox.documentation.annotations.ApiIgnore;

/**
 * <p>
 * 设备续费订单 前端控制器
 * </p>
 *
 * @author 若尘
 * @since 2022-02-21
 */
@Slf4j
@RestController
@RequestMapping("/orderEntity")  
@Api(tags = "订单模块")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderController extends BaseServiceImpl<OrderMapper, OrderEntity> {

	private final OrderService orderService;
	private final AccountService accountService;
	private final UserService userService;
	private final ProductServiceService productServiceService;
	private final PayRecordService payRecordService;
	private final RefunRecordService refunRecordService;
	private final WalletRecordService walletRecordService;
	private final WxMaService wxMaService;
	private final ServiceOrderService  serviceOrderService;
	private final PubPayService  pubPayService;
	private final WxPayServices2  wxPayServices2;
	
	@Qualifier("productStoceLock")
	@Autowired
	private  AmountLockService productStoceLock;
	
	@Value("${payInfo.test}")
    private Integer PayTest = 1;

	private QueryWrapper<OrderEntity>  getCondition(BaseFilterPageReq<OrderEntity> req) {
		UserDto uDto = ShiroUtil.getPrincipalUser();
		QueryWrapper<OrderEntity> t = new QueryWrapper<OrderEntity>();
		if (StringUtils.isNotBlank(req.getStartTime()))
			t.ge("o.create_time", req.getStartTime());
		if (StringUtils.isNotBlank(req.getEndTime()))
			t.le("o.create_time", req.getEndTime());
		
		t.eq("o.pay_status", 1);
		if (req.getEntityParam()!=null ) {
			if(req.getEntityParam().getUserId()!=null)
				t.eq("o.user_id ", req.getEntityParam().getUserId());
			if(StringUtils.isNotBlank(req.getEntityParam().getOrderNo()))
				t.eq( "o.order_no", req.getEntityParam().getOrderNo());
		}
		if(Assert.isNonEmpty(req.getIncludeIds())) 
			t.in("status",req.getIncludeIds());
		
		if (null != req.getKeyWords() && req.getKeyWords().size() > 0) {
			if (req.getKeyWords().containsKey("productName")) {
				JSONObject  j = new JSONObject();
				j.put("productName", req.getKeyWords().getString("productName"));
				t.apply(getLikeStr(j, "d."));
				req.getKeyWords().remove("productName");
			}
			if(req.getKeyWords().size()>0)
				t.apply(getLikeStr(req.getKeyWords(), "o."));			
		}
		 
		
		return t;
	}
	
	@ApiOperation(value = "获取订单详情不分页列表")
	@RequestMapping(value = "/getOrderDetailList", method = RequestMethod.POST)
	public CodeDataResp<List<OrderVO>> getOrderDetailList(@RequestBody @NotNull BaseFilterPageReq<OrderEntity> req) {

		QueryWrapper<OrderEntity> t =	getCondition(req);
		
		List<OrderVO> result = this.getBaseMapper().getOrderDetailList(t);
		return CodeDataResp.valueOfSuccess(result);
	}
	
	@ApiOperation(value = "获取订单详情分页列表")
	@RequestMapping(value = "/getOrderDetailPage", method = RequestMethod.POST)
	public CodeDataResp<Page<OrderVO>> getOrderDetailPage(@RequestBody BaseFilterPageReq<OrderEntity> req) {
		UserDto uDto = ShiroUtil.getPrincipalUser();

		Page<XcxUserOrderCountVO> page = MpPageUtil.getCommonPage(req.getPageReq());
		
		QueryWrapper<OrderEntity> t =	getCondition(req);
		
		Page<OrderVO> result = this.getBaseMapper().customisePage(page	, t);
		return CodeDataResp.valueOfSuccess(result);

	}
	
	@ApiOperation(value = "退货")
	@RequestMapping(value = "/refund2", method = RequestMethod.GET)
	public CodeDataResp refund2(@RequestParam String orderNo) {
		QueryWrapper<OrderEntity>  qw = new QueryWrapper<OrderEntity>();
		qw.lambda().eq(OrderEntity :: getOrderNo, orderNo).last(" limit 1 ");
		OrderEntity source = this.orderService.getOne(qw);

		return CodeDataResp.valueOfSuccessEmptyData();
	}
	
	@ApiOperation(value = "退款")
	@RequestMapping(value = "/refund", method = RequestMethod.GET)
	@Transactional(rollbackFor = Exception.class)
	public CodeDataResp refund(@RequestParam String serviceOrderId) {
		ServiceOrderEntity  target  = this.serviceOrderService.getById(serviceOrderId);
		if(target == null)
			return CodeDataResp.valueOfFailed("订单不存在");
		
		
			OrderEntity source = this.orderService.getById(target.getOrderId());
			PayRecord  p = this.payRecordService.getById(source.getPayRecordId());
			p.setStatus((byte) -2);
			source.setStatus(-2);//退款
			target.setRefundDate(new Date());
			target.setPayStatus(-2); 
			target.setStatus(-2);
			target.setRefundDate(new Date());
			if(target.getRefundFlag()>0)
				target.setRefundFlag(3);
			
			RefunRecordEntity refunRecord = new RefunRecordEntity();
			refunRecord.setRefunOrderId(target.getOrderId().toString());
			refunRecord.setRefundMoney(p.getPayMoney());
			refunRecord.setPayCode(p.getTransactionId());
			refunRecord.setTotalMoney(source.getPayableFee());
			refunRecord.setOutRefundNo(p.getOrderNo());
			Boolean flag = this.wxPayServices2.sendRefund(refunRecord);
//            Boolean flag = this.pubPayService.sendRefund(refunRecord,wxMaMiniAppCfg);
			this.refunRecordService.save(refunRecord);
			if(flag == true) {
				this.payRecordService.updateById(p);
				this.serviceOrderService.updateById(target);
				this.updateById(source);				
			}else {
				return CodeDataResp.valueOfFailed("退款失败，网络异常，请联系客服");
			} 		
	
		return CodeDataResp.valueOfSuccessEmptyData();
	}
	private final CompanyEntity wxMaMiniAppCfg;
	
	@ApiOperation(value = "手动退款")
	@RequestMapping(value = "/refund3", method = RequestMethod.GET)
	public CodeDataResp refund3(@RequestParam String id) {
		OrderEntity source = this.orderService.getById(id);
		this.updateById(source);

			QueryWrapper<PayRecord> qw2 = new QueryWrapper<PayRecord>();
			qw2.lambda().eq(PayRecord :: getOrderId, source.getId()).last(" limit 1 ");
			PayRecord  p = payRecordService.getOne(qw2);
			RefunRecordEntity refunRecord = new RefunRecordEntity();
			refunRecord.setRefunOrderId(id);
			refunRecord.setRefundMoney(p.getPayMoney());
			refunRecord.setPayCode(p.getTransactionId());
			refunRecord.setTotalMoney(source.getPayableFee());
			Date currentDate = new Date();
			StringBuilder sb = new StringBuilder("T");
			sb.append(DateUtils.format(currentDate, DateUtils.DATE_TIME_FORMAT_NUMBER))
					.append(StrUtils.generateZeroCharacter(id, 6, "0")).append("0")
					.append(StrUtils.randomnum(999, 99999));
			refunRecord.setOutRefundNo(sb.toString());
			Boolean flag = this.wxPayServices2.sendRefund(refunRecord);
//			Boolean flag = this.pubPayService.HLRefund(refunRecord);
			this.refunRecordService.save(refunRecord);
		
	
		return CodeDataResp.valueOfSuccessEmptyData();
	}
	


	@ApiOperation(value = "获取列表")
	@RequestMapping(value = "/getList", method = RequestMethod.POST)
	public CodeDataResp<List<OrderEntity>> getList(@RequestBody BaseFilterPageReq<OrderEntity> req) {

		QueryWrapper<OrderEntity> t = new QueryWrapper<OrderEntity>();
		UserDto user = ShiroUtil.getPrincipalUser();

		if (null != req.getKeyWords() && req.getKeyWords().size() > 0)
			t.apply(getLikeStr(req.getKeyWords(), ""));
		t.setEntity(req.getEntityParam());
		return CodeDataResp.valueOfSuccess(super.list(t));
	}

	/**
	 * 创建订单
	 * @throws WxErrorException 
	 */
	@ApiOperation(value = "创建服务订单")
	@RequestMapping(value = "/planceOrder", method = RequestMethod.POST)
	@Transactional(rollbackFor = Exception.class)
	public CodeDataResp<JSONObject> planceOrder(@RequestBody  PlaceOrderReq  req) throws WxErrorException {
			UserEntity user = this.userService.getById(ShiroUtil.getPrincipalUserId());
		//补全数据
			ProductServiceEntity  products = this.productServiceService.getById(req.getProductServiceId());
			if(products == null)
				return CodeDataResp.valueOfFailed("服务不存在");
			try {
					String bannerImg =  products.getBannerImg();
					ServiceOrderEntity  item = new ServiceOrderEntity();
					item.setBannerImg(bannerImg)
					.setPaidAmount(products.getServicePrice())
					.setPayableMoney( products.getServicePrice())
					.setPayStatus(0)
					.setPayWay(req.getPayWay())
					.setRemark(req.getRemark())
					.setServiceId(Integer.parseInt(products.getId()))
					.setServicePrice(products.getServicePrice())
					.setServiceTitle(products.getServiceTitle())
					.setUserId(Integer.parseInt(user.getId()))
					.setUserName(user.getNickName())
					.setUserPhone(user.getUserPhone())
					.setServiceTitle(products.getServiceName())
					.setServiceType(products.getServiceType())
					;
					this.serviceOrderService.save(item);
//				// 生成订单
				OrderEntity order = orderService.createOrder(OrderSource.PlaceOrder,products.getServiceTitle(),user,item.getPayableMoney(),item.getId());
				item.setOrderId(Integer.parseInt( order.getId()))
					.setOrderNo(order.getOrderNo());
				this.serviceOrderService.updateById(item);
				return	orderService.placeOrder(order, PayWayDict.WxPayway);
			}catch (Exception e) {
				throw e;
			}

	}
	
	private final CompanyService companyService;
	
	
	/**
	 * 创建订单
	 */
	@ApiOperation(value = "拉起微信小程序支付")
	@RequestMapping(value = "/settle", method = RequestMethod.GET)
	@Transactional(rollbackFor = Exception.class)
	public CodeDataResp settle(@RequestParam @NotNull Integer orderId,@RequestParam @NotNull Byte payWay,@RequestParam @NotNull String redictParam) {
		OrderEntity  o =	this.getById(orderId);
		if(!o.getPayStatus().equals((byte)0))
			return CodeDataResp.valueOfFailed("不是待支付状态");
		
		return	orderService.placeOrder(o, PayWayDict.WxPayway);
	
	}
	
	

	@ApiOperation(value = "确认订单发货")
	@RequestMapping(value = "/sendOrder", method = RequestMethod.GET)
	@Transactional(rollbackFor = Exception.class)
	public CodeDataResp sendOrder(@RequestParam @NotNull Integer orderId) throws WxErrorException {
		OrderEntity  order = this.getById(orderId);
		QueryWrapper<PayRecord> qw = new QueryWrapper<PayRecord>();
		qw.lambda().eq(PayRecord :: getOrderId, orderId)
					.eq(PayRecord :: getStatus, 1)
					.eq(PayRecord :: getUserId, order.getUserId());
		PayRecord p =	this.payRecordService.getOne(qw);
		if(p == null)
			return CodeDataResp.valueOfFailed("无效订单");
		
		return CodeDataResp.valueOfSuccess(null);
	}


	
	

	

	

	@ApiOperation(value = "导出对账清单列表")
	@PostMapping("/export")
	public CodeDataResp export(@RequestBody BaseFilterPageReq<OrderEntity> req) {
		
		UserDto uDto = ShiroUtil.getPrincipalUser();
		
		QueryWrapper<OrderEntity> t =	getCondition(req);
		t.orderByDesc(req.getPageReq().getSortType());
		List<OrderRecordVO>  exportData = this.getBaseMapper().customiseExport(t);
		if(Assert.isEmpty(exportData))
			return CodeDataResp.valueOfSuccess(null);
//		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
//		response.setCharacterEncoding("utf-8");
//		String fileName = URLEncoder.encode("人员信息.xlsx", "UTF-8");
//		response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
		String name = "订单列表";
		String fileName = DatePattern.PURE_DATETIME_FORMAT.format(new Date()) + name + ".xlsx";
		String folderStr = "excel".concat(File.separator).concat("export");
		String userDir = System.getProperties().getProperty("user.dir").concat(File.separator).concat("static");
//		String userDir = "D://bom".concat(File.separator).concat("static");
		String uploadPath = userDir.concat(File.separator).concat(folderStr);
		String filePath = uploadPath.concat(File.separator).concat(fileName);
		String returnPath = "excel".concat("/").concat("export").concat("/").concat(fileName);
		log.info("保存路径：{},返回地址{}", filePath, returnPath);
		EasyExcel.write(filePath, OrderRecordVO.class).sheet(name).doWrite(exportData);

		return CodeDataResp.valueOfSuccess(returnPath);
	}




	@ApiOperation(value = "取消支付")
	@RequestMapping(value = "/canclePay/{id}", method = RequestMethod.GET)
	public CodeDataResp canclePay(@PathVariable String id) {
		OrderEntity o = this.getById(id);
		if (Objects.equals(o.getPayStatus(), (byte) 2)) {
			o.setId(id);
			o.setPayStatus((byte) 0);
			o.setStatus(0);
			this.updateById(o);
		}
		return CodeDataResp.valueOfSuccessEmptyData();
	}

	@ApiIgnore
	@ApiOperation(value = "测试拉起微信支付")
	@RequestMapping(value = "/demo", method = RequestMethod.GET)
	public CodeDataResp demo(String openid, HttpServletRequest request) {
		final String WxPayKey2 = "Dk6dRsDWWQwSzfWwM46fdsMK086e895e";
		final String appId = "wx2b434db30470224f";
		final String notifyUrl = "http://szcxmx.gnway.cc/api/orderEntity/wxNotify";
		PayRecord payRecord = new PayRecord();
		String ip = IpUtil.getIpAddr(request);
		Integer total_fee = 1;
		SortedMap<String, Object> param = new TreeMap<>();
		param.put("appid", appId);
		param.put("mch_id", "1526955481");
		String nonce_str = String.valueOf(new Date().getTime());
		param.put("nonce_str", nonce_str);
		param.put("body", payRecord.getPayName());// 商品描述
		param.put("out_trade_no", payRecord.getOrderNo());// 订单号(PAY*)
		param.put("total_fee", "" + total_fee);// 交易金额 单位：分
		param.put("spbill_create_ip", ip);
		param.put("notify_url", notifyUrl);// 回调地址
		param.put("trade_type", "JSAPI");
		param.put("openid", openid);
		// 转QuseryString字符串
		String xmlStr = XmlUtils.paramSort(param, WxPayKey2);

		System.out.println("\n 请求的xml参数为：" + xmlStr);
		String resultStr = HttpPostUtil.sendPost(WxAppPayConfig.WxPayMent, xmlStr);

		System.out.println("本次下单结果：" + resultStr);
		if (StringUtils.isBlank(resultStr)) {
			throw new ApiException("请求异常");
		}
		JSONObject resultMap = new JSONObject();
		Map<String, String> resultMap1 = null;
		try {
			resultMap1 = XmlUtils.toMap(resultStr.getBytes(), "utf-8");

			JSONObject result = (JSONObject) JSONObject.toJSON(resultMap1);

			StringBuilder subStr = new StringBuilder("");
			if (!result.get("return_code").equals("SUCCESS")) {
				subStr.append("\n 通信失败,");
				subStr.append(" \n 请求状态：");
				subStr.append(result.get("return_code"));
				subStr.append("\t ,错误描述：");
				subStr.append(result.get("return_msg"));
				log.error(subStr.toString());
				payRecord.setIsExpire((byte) 1);// 失效
				payRecord.setStatus((byte) -1);// 错误状态
				payRecord.setStatusDesc(subStr.toString());
				throw new ApiException(State.CODE_FAILED, subStr.toString());
			} else {
				if (result.get("result_code").equals("SUCCESS")) {
					String prepay_id = result.getString("prepay_id");
					resultMap = SignUtils.createPayParams(appId, nonce_str, nonce_str, prepay_id, WxPayKey2);
					// 拉起收银成功状态改为正在支付
					payRecord.setStatus((byte) 2);
					payRecord.setStatusDesc("拉起收银台成功,正在支付...");
				} else {
					log.error(resultStr);
					subStr.append("\n 拉起微信官方支付失败：");
					subStr.append(result.getString("result_code"));
					subStr.append(" \n 通信状态：");
					subStr.append(result.get("return_code"));
					subStr.append("\t ,通信描述：");
					subStr.append(result.get("return_msg"));
					subStr.append("\t ,错误码：");
					subStr.append(result.get("err_code"));
					subStr.append("\t ,错误描述：");
					subStr.append(result.get("return_msg"));
					subStr.append("\t ,系统错误描述：");
					subStr.append(result.get("err_code_des"));
					log.error(" 拉起微信官方支付失败：\n" + resultStr);
					payRecord.setIsExpire((byte) 1);// 失效
					payRecord.setStatus((byte) -1);// 错误状态
					payRecord.setStatusDesc(subStr.toString());
					throw new ApiException(State.CODE_FAILED, subStr.toString());
				}
			}
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return CodeDataResp.valueOfSuccess(resultMap);
	}

}
